pacman::p_load(dplyr, readr, sf, tidyverse, tmap, sfdep, ggpubr, Metrics, ggplot2, plotly, spdep, rjson, od, gifski, stplanr)This article and analysis is a work-in-progress! Read the results at your own risk!
1 Overview
1.1 Issue
Given the
1.2 Objectives
Understand more about the initial failure of the route rationalisation of bus service 167:
- Commuters perspective
- Why a hub-and-spoke approach (with the introduction of Thomson East Coast Line) is insufficient to shift demand?
Click here to skip to the analysis
2 Getting Started
2.1 Setting Up
Packages required to be loaded for
2.2 Data Sources
| Dataset Name | Source | Methodology |
|---|---|---|
| Origin-Destination Passenger Count for Buses (OD) Nov 2023 | LTA Datamall | API |
| Bus Routes as of 26 Nov 2023 | LTA Datamall | API |
| Bus Stops as of 26 Nov 2023 | LTA Datamall | API |
3 Data Preparation
3.1 Loading Data
Loading the Origin-Destination Passenger Count for Buses
OD_2023_11 <- read.csv("data/167_OD_analysis/origin_destination_bus_202311.csv")Loading the Bus Routes JSON file:
BUS_ROUTE <- fromJSON(file="data/167_OD_analysis/busroute_2023-11-26.json")Loading the Bus Stops JSON file:
BUS_STOP <- fromJSON(file="data/167_OD_analysis/busstop_2023-11-26.json")Load MPSZ (2019):
mpsz <- st_read(dsn = "data/167_OD_analysis/",
layer = "MPSZ-2019") %>%
st_transform(crs = 3414)Reading layer `MPSZ-2019' from data source
`C:\Users\boylu\OneDrive - Singapore Management University\0_git-projects\urbancoalesce\explore\data\167_OD_analysis'
using driver `ESRI Shapefile'
Simple feature collection with 332 features and 6 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 103.6057 ymin: 1.158699 xmax: 104.0885 ymax: 1.470775
Geodetic CRS: WGS 84
3.2 Extracting Relevant Information
For the OD Passenger Count, we are only interested in obtaining counts which involves bus service 167. We will need to extract it twice, once for each direction.
We are not implementing a check for stops since the JSON data from LTA Datamall is returned in stop sequence.
3.2.1 Extract 167 Bus Stops
As LTA’s OD Count stores CBD area bus stops starting with 0 as 4 digit codes instead of 5 digit prefixed with 0, we recode the bus stops as numeric and drop the ‘0’ prefix
BS_167_DIR_1_DF <- data.frame(Seq = integer(), BS_Code = integer())
BS_167_DIR_2_DF <- data.frame(Seq = integer(), BS_Code = integer())
for (route_info in BUS_ROUTE){
if (route_info$ServiceNo == "167"){
if (route_info$Direction == 1){
BS_167_DIR_1_temp <- data.frame(Seq = as.numeric(route_info$StopSequence), BS_Code = as.numeric(route_info$BusStopCode))
BS_167_DIR_1_DF[nrow(BS_167_DIR_1_DF) +1,] <- BS_167_DIR_1_temp
}
else if (route_info$Direction == 2){
BS_167_DIR_2_temp <- data.frame(Seq = as.numeric(route_info$StopSequence), BS_Code = as.numeric(route_info$BusStopCode))
BS_167_DIR_2_DF[nrow(BS_167_DIR_2_DF) +1,] <- BS_167_DIR_2_temp
}
}
}
rm(BS_167_DIR_1_temp)
rm(BS_167_DIR_2_temp)3.2.2 Append Bus Stop Names to DataFrame
We convert the List format of Bus Stops to a more workable DataFrame format
BUS_STOP_DF <- data.frame(BS_Code = integer(), BS_Road_Name = character(), BS_Name = character(), Latitude = double(), Longitude = double())
for (bs in BUS_STOP){
BS_TEMP <- data.frame(BS_Code = as.numeric(bs$BusStopCode), BS_Road_Name = bs$RoadName, BS_Name = bs$Description, Latitude = as.numeric(bs$Latitude), Longitude = as.numeric(bs$Longitude))
BUS_STOP_DF[nrow(BUS_STOP_DF) +1,] <- BS_TEMP
}
rm(BS_TEMP)We then do a left join, merging the bus stop info into Bus Service direction DataFrames
BS_167_DIR_1_DF <- merge(x=BS_167_DIR_1_DF,y=BUS_STOP_DF,
by="BS_Code", all.x=TRUE)
BS_167_DIR_2_DF <- merge(x=BS_167_DIR_2_DF,y=BUS_STOP_DF,
by="BS_Code", all.x=TRUE)3.2.3 Reset Row Index Numbering
rownames(BS_167_DIR_1_DF) <- BS_167_DIR_1_DF$Seq
rownames(BS_167_DIR_2_DF) <- BS_167_DIR_2_DF$Seq4 Exploratory Data Analysis
Investigating the Bus Stops on Bus Service 167
71 Stops
BS_167_DIR_1_DF[order(BS_167_DIR_1_DF$Seq),] BS_Code Seq BS_Road_Name BS_Name Latitude Longitude
1 58009 1 Sembawang Vista Sembawang Int 1.447482 103.8194
2 58151 2 Canberra Rd Bef Sembawang Stn 1.448359 103.8220
3 58331 3 Canberra Link Blk 589D 1.449741 103.8240
4 58039 4 Sembawang Rd Bef Canberra Dr 1.446742 103.8258
5 58029 5 Sembawang Rd The Nautical 1.443159 103.8240
6 58019 6 Sembawang Rd Aft Sembawang Shop Ctr 1.440850 103.8247
7 57139 7 Sembawang Rd Aft Jln Kemuning 1.437957 103.8256
8 57129 8 Sembawang Rd Blk 114 1.434187 103.8264
9 57119 9 Sembawang Rd Blk 101 1.431303 103.8269
10 57089 10 Sembawang Rd Blk 713 1.427405 103.8269
11 57079 11 Sembawang Rd Khatib Camp 1.424439 103.8257
12 57069 12 Sembawang Rd Opp Dieppe Barracks 1.418966 103.8246
13 57059 13 Sembawang Rd Opp Sembawang Air Base 1.414728 103.8236
14 57049 14 Sembawang Rd Opp Nee Soon HQ 22 SIB 1.410820 103.8223
15 57039 15 Sembawang Rd SPIRITUAL GRACE PRESBY CH 1.406118 103.8200
16 57029 16 Sembawang Rd Aft The Springside 1.403963 103.8186
17 57019 17 Upp Thomson Rd Springleaf Nature Pk 1.400563 103.8173
18 56099 18 Upp Thomson Rd Springleaf Stn Exit 2 1.396068 103.8188
19 56089 19 Upp Thomson Rd Aft SLE 1.392051 103.8186
20 56079 20 Upp Thomson Rd Aft Old Upp Thomson Rd 1.387566 103.8196
21 56069 21 Upp Thomson Rd Bef Tagore Dr 1.385305 103.8232
22 56059 22 Upp Thomson Rd Bef Tagore Rd 1.382688 103.8260
23 56049 23 Upp Thomson Rd Meadows @ Peirce 1.379456 103.8277
24 56039 24 Upp Thomson Rd Aft Yio Chu Kang Rd 1.376731 103.8285
25 56029 25 Upp Thomson Rd Bef Sembawang Hills Fc 1.373595 103.8287
26 56019 26 Upp Thomson Rd Bef Ang Mo Kio Ave 1 1.369486 103.8286
27 53099 27 Upp Thomson Rd Aft Ang Mo Kio Ave 1 1.366606 103.8284
28 53089 28 Upp Thomson Rd Faber Gdn 1.363977 103.8282
29 53079 29 Upp Thomson Rd Flame Tree Pk 1.360827 103.8286
30 53069 30 Upp Thomson Rd Aft Windsor Pk Rd 1.357772 103.8289
31 53059 31 Upp Thomson Rd Upp Thomson Stn Exit 2 1.355471 103.8312
32 53049 32 Upp Thomson Rd Bef Jln Todak 1.353627 103.8342
33 53039 33 Upp Thomson Rd Thomson CC 1.351447 103.8359
34 53029 34 Upp Thomson Rd Shunfu Est 1.349392 103.8373
35 53019 35 Upp Thomson Rd OPP ST. THERESA'S HME 1.346003 103.8387
36 51069 36 Thomson Rd Mt Alvernia Hosp 1.341258 103.8366
37 51059 37 Thomson Rd AFT TOA PAYOH RISE 1.337033 103.8374
38 51049 38 Thomson Rd SLF Cplx 1.333821 103.8380
39 51039 39 Thomson Rd Opp S'pore Polo Club 1.331658 103.8389
40 51029 40 Thomson Rd Opp Old Police Acad 1.330255 103.8397
41 51019 41 Thomson Rd Thomson Flyover 1.328942 103.8407
42 50059 42 Thomson Rd Opp Thomson Med Ctr 1.325264 103.8422
43 50049 43 Thomson Rd Opp Novena Lodge 1.323541 103.8419
44 50037 44 Thomson Rd Bef Novena Stn Exit B 1.321100 103.8422
45 50069 45 Newton Rd Hotel Royal 1.317022 103.8416
46 40129 46 Newton Rd Newton Life Ch 1.314538 103.8408
47 40189 47 Scotts Rd Newton Stn Exit B 1.312274 103.8381
48 40179 48 Scotts Rd Env Bldg 1.311332 103.8369
49 9219 49 Scotts Rd Far East Plaza 1.307320 103.8332
50 9047 50 Orchard Rd Orchard Stn/Tang Plaza 1.304461 103.8329
51 9037 51 Orchard Rd Bef Cairnhill Rd 1.302340 103.8370
52 8138 52 Orchard Rd Concorde Hotel S'pore 1.300479 103.8418
53 8057 53 Orchard Rd Dhoby Ghaut Stn 1.299310 103.8453
54 8069 54 Bras Basah Rd Bencoolen Stn Exit B 1.298214 103.8494
55 4179 55 Bras Basah Rd Aft Bras Basah Stn Exit A 1.296479 103.8515
56 2049 56 Bras Basah Rd Raffles Hotel 1.294521 103.8540
57 2029 57 Esplanade Dr Aft Esplanade Stn Exit D 1.290106 103.8546
58 3019 58 Collyer Quay OUE Bayfront 1.284245 103.8531
59 3059 59 Raffles Quay One Raffles Quay 1.281111 103.8515
60 3129 60 Shenton Way UIC Bldg 1.278070 103.8496
61 3218 61 Shenton Way Opp MAS Bldg 1.274079 103.8469
62 5631 62 Cantonment Link Blk 16 1.273461 103.8403
63 5521 63 Cantonment Rd Maritime Hse 1.276769 103.8406
64 10021 64 Neil Rd Blk 3 1.277448 103.8384
65 10041 65 Kg Bahru Rd BEF KAMPONG BAHRU TER 1.276058 103.8352
66 10051 66 Jln Bt Merah Blk 149 1.277412 103.8321
67 10061 67 Jln Bt Merah Blk 140 1.278605 103.8295
68 10071 68 Jln Bt Merah Blk 111 1.280453 103.8264
69 10501 69 Jln Bt Merah Blk 104 1.281058 103.8253
70 10081 70 Jln Bt Merah Opp Blk 120 1.282278 103.8224
71 10009 71 Bt Merah Ctrl Bt Merah Int 1.282102 103.8172
69 Stops
BS_167_DIR_2_DF[order(BS_167_DIR_2_DF$Seq),] BS_Code Seq BS_Road_Name BS_Name Latitude Longitude
1 10009 1 Bt Merah Ctrl Bt Merah Int 1.282102 103.8172
2 10089 2 Jln Bt Merah Blk 119 1.282923 103.8217
3 10079 3 Jln Bt Merah Blk 201 1.280395 103.8271
4 10069 4 Jln Bt Merah Opp Blk 140 1.278555 103.8301
5 10059 5 Jln Bt Merah Opp Blk 149 1.277397 103.8328
6 10049 6 Kg Bahru Rd OPP KAMPONG BAHRU TER 1.276233 103.8348
7 10017 7 Eu Tong Sen St Aft Hosp Dr 1.278320 103.8376
8 5519 8 Cantonment Rd Blk 1G 1.275535 103.8411
9 5629 9 Cantonment Rd Opp Southpoint 1.273211 103.8419
10 3223 10 Anson Rd Tanjong Pagar Stn Exit C 1.275703 103.8463
11 3151 11 Cecil St Opp GB Bldg 1.278921 103.8478
12 3021 12 Cecil St Prudential Twr 1.282555 103.8500
13 3011 13 Fullerton Rd Fullerton Sq 1.285618 103.8534
14 2111 14 Esplanade Dr Esplanade Bridge 1.290956 103.8545
15 4111 15 Stamford Rd Capitol Bldg 1.293954 103.8514
16 4121 16 Stamford Rd SMU 1.296185 103.8496
17 8041 17 Orchard Rd YMCA 1.298110 103.8478
18 8031 18 Penang Rd Dhoby Ghaut Stn Exit B 1.298312 103.8453
19 8111 19 Penang Rd Winsland Hse 1.299869 103.8409
20 8121 20 Somerset Rd Somerset Stn 1.300276 103.8388
21 9011 21 Orchard Turn Opp Ngee Ann City 1.302113 103.8343
22 9023 22 Orchard Turn Opp Orchard Stn/ION 1.303237 103.8325
23 9212 23 Scotts Rd Royal Plaza On Scotts 1.307022 103.8327
24 40171 24 Scotts Rd Opp Env Bldg 1.310952 103.8358
25 40181 25 Scotts Rd Newton Stn Exit A 1.312641 103.8383
26 40121 26 Newton Rd Opp Newton Life Ch 1.314582 103.8405
27 50061 27 Newton Rd Opp Hotel Royal 1.317435 103.8414
28 50031 28 Thomson Rd Opp Novena Ch 1.321378 103.8417
29 50041 29 Thomson Rd Novena Lodge 1.323623 103.8416
30 50051 30 Thomson Rd Thomson Med Ctr 1.325878 103.8418
31 51011 31 Thomson Rd Opp Tan Tong Meng Twr 1.327842 103.8406
32 51021 32 Thomson Rd Old Police Acad 1.330411 103.8391
33 51031 33 Thomson Rd S'pore Polo Club 1.331629 103.8386
34 51051 34 Thomson Rd AFT ANDREW RD 1.336354 103.8371
35 51071 35 Thomson Rd MacRitchie Resvr 1.342193 103.8360
36 53011 36 Upp Thomson Rd ST. THERESA'S HME 1.345554 103.8383
37 53021 37 Upp Thomson Rd Lakeview Estate 1.349680 103.8365
38 53041 38 Upp Thomson Rd Bef Thomson Ridge 1.353099 103.8343
39 53051 39 Upp Thomson Rd Upp Thomson Stn Exit 5 1.354995 103.8316
40 53061 40 Upp Thomson Rd Bef Windsor Pk Rd 1.357158 103.8288
41 53071 41 Upp Thomson Rd Opp Flame Tree Pk 1.360633 103.8283
42 53081 42 Upp Thomson Rd Opp Faber Gdn 1.363193 103.8278
43 53091 43 Upp Thomson Rd Bef Ang Mo Kio Ave 1 1.364820 103.8279
44 56011 44 Upp Thomson Rd Bef adana at thomson 1.368650 103.8283
45 56021 45 Upp Thomson Rd Opp Sembawang Hills FC 1.372666 103.8284
46 56031 46 Upp Thomson Rd Bef Yio Chu Kang Rd 1.376957 103.8282
47 56041 47 Upp Thomson Rd Opp Meadows @ Peirce 1.379094 103.8276
48 56051 48 Upp Thomson Rd Opp Tagore Rd 1.382495 103.8258
49 56061 49 Upp Thomson Rd Aft Tagore Dr 1.385154 103.8229
50 56071 50 Upp Thomson Rd Bef Old Upp Thomson Rd 1.387177 103.8196
51 56081 51 Upp Thomson Rd Bef SLE 1.391569 103.8182
52 56091 52 Upp Thomson Rd Springleaf Stn Exit 3 1.396200 103.8185
53 57011 53 Upp Thomson Rd Opp Springleaf Nature Pk 1.400157 103.8172
54 57021 54 Sembawang Rd Forest Hills Condo 1.404141 103.8183
55 57031 55 Sembawang Rd Nee Soon Driclad Ctr 1.407054 103.8201
56 57041 56 Sembawang Rd Nee Soon HQ 22 SIB 1.410693 103.8219
57 57051 57 Sembawang Rd Aft Sembawang Air Base 1.415206 103.8234
58 57061 58 Sembawang Rd Dieppe Barracks 1.419905 103.8245
59 57071 59 Sembawang Rd Opp Khatib Camp 1.424958 103.8255
60 57081 60 Sembawang Rd Opp Blk 713 1.427536 103.8266
61 57111 61 Sembawang Rd Opp Blk 101 1.431236 103.8265
62 57121 62 Sembawang Rd Opp Blk 115B 1.433451 103.8263
63 57131 63 Sembawang Rd Opp Jln Kemuning 1.438084 103.8253
64 58011 64 Sembawang Rd Opp Sembawang Shop Ctr 1.441356 103.8242
65 58021 65 Sembawang Rd Opp The Nautical 1.443241 103.8237
66 58031 66 Sembawang Rd Opp Canberra Dr 1.446287 103.8250
67 58339 67 Canberra Link Opp Blk 589D 1.449361 103.8243
68 58159 68 Canberra Rd Aft Admiral Hill 1.448217 103.8224
69 58009 69 Sembawang Vista Sembawang Int 1.447482 103.8194
sf_BS_167_DIR_1 <- st_as_sf(BS_167_DIR_1_DF, coords = c("Longitude", "Latitude"), crs = 4326)
sf_BS_167_DIR_2 <- st_as_sf(BS_167_DIR_2_DF, coords = c("Longitude", "Latitude"), crs = 4326)
sf_BS_167_DIR_1 <- st_transform(sf_BS_167_DIR_1, crs = 3414)
sf_BS_167_DIR_2 <- st_transform(sf_BS_167_DIR_2, crs = 3414)tmap_mode("view")
tm_shape(sf_BS_167_DIR_1) +
tm_dots(col = "red") +
tm_shape(sf_BS_167_DIR_2) +
tm_dots(col = "blue")OD_2023_11_DIR1TEST <- left_join(OD_2023_11_DIR1, BUS_STOP_DF,
by=c("ORIGIN_PT_CODE" = "BS_Code"))
OD_2023_11_DIR1TEST <- left_join(OD_2023_11_DIR1TEST, BUS_STOP_DF,
by=c("DESTINATION_PT_CODE" = "BS_Code"), suffix=c("_ORIGIN", "_DEST"))
sf_BS_167_DIR_1test <- sf_BS_167_DIR_1[c(1,4)]gen_od_timing <- function(input_OD, sf_bs, timing){
OD_TEST_DIR1 <- input_OD %>% filter(DAY_TYPE == "WEEKDAY" & TIME_PER_HOUR == timing)
OD_TEST_DIR1 <- OD_TEST_DIR1[5:7]
sf <- od_to_sf(OD_TEST_DIR1, sf_bs)
return (sf)
}
tmap_plot_route <- function(BS, OD) {
tmap_mode("view")
tm_shape(BS) +
tm_dots(col = "magenta", scale = 1.3) +
#tm_shape(sf_BS_167_DIR_2) +
# tm_dots(col = "blue", scale = 2) +
tm_shape(OD) +
tm_lines("TOTAL_TRIPS", style="fixed", breaks = c(0, 25, 50, 100, 250, 500, 700, 1000, 1500, 2500), lwd = "TOTAL_TRIPS", scale=15, palette="viridis")
}
plot_trip_summary <- function(OD){
summary(OD$TOTAL_TRIPS)
p <- ggplot(OD, aes(x=TOTAL_TRIPS)) +
geom_histogram(binwidth=100) +
xlim(0, 2500) +
ylim(0, 400)
ggplotly(p)
}temp_sf <- gen_od_timing(OD_2023_11_DIR1, sf_BS_167_DIR_1, 6)
tmap_plot_route(sf_BS_167_DIR_1, temp_sf)temp_sf %>% arrange(desc(TOTAL_TRIPS))Simple feature collection with 856 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26208.89 ymin: 28438.32 xmax: 30372.89 ymax: 47930.55
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PT_CODE DESTINATION_PT_CODE TOTAL_TRIPS
1 40189 9219 819
2 56099 56059 695
3 57029 56099 429
4 56029 53059 268
5 8057 2049 227
6 8057 8069 211
7 56019 53059 195
8 56059 53059 175
9 40189 40179 161
10 57079 56099 133
geometry
1 LINESTRING (28532.13 32730....
2 LINESTRING (26387.61 41995....
3 LINESTRING (26364.54 42868....
4 LINESTRING (27486.01 39510....
5 LINESTRING (29332.34 31296....
6 LINESTRING (29332.34 31296....
7 LINESTRING (27476.66 39056....
8 LINESTRING (27190.6 40516.1...
9 LINESTRING (28532.13 32730....
10 LINESTRING (27148.6 45132.7...
plot_trip_summary(temp_sf)temp_sf <- gen_od_timing(OD_2023_11_DIR1, sf_BS_167_DIR_1, 7)
tmap_plot_route(sf_BS_167_DIR_1, temp_sf)plot_trip_summary(temp_sf)temp_sf <- gen_od_timing(OD_2023_11_DIR1, sf_BS_167_DIR_1, 8)
tmap_plot_route(sf_BS_167_DIR_1, temp_sf)plot_trip_summary(temp_sf)temp_sf <- gen_od_timing(OD_2023_11_DIR1, sf_BS_167_DIR_1, 9)
tmap_plot_route(sf_BS_167_DIR_1, temp_sf)plot_trip_summary(temp_sf)Animation of 24hrs

i_time = 5
tm_objs = list()
while (i_time < 24){
temp_sf <- gen_od_timing(OD_2023_11_DIR1, sf_BS_167_DIR_1, i_time)
result = paste("Bus Service 167 Weekday: Hour ", i_time, sep = " ")
temp_tm <-
#tm_shape(sf_BS_167_DIR_2) +
# tm_dots(col = "blue", scale = 2) +
tm_shape(mpsz, bbox = c(22000, 27000, 34000, 49000)) +
tm_polygons(alpha=0) +
tm_shape(temp_sf) +
tm_lines("TOTAL_TRIPS", style="fixed", breaks = c(0, 25, 50, 100, 250, 500, 700, 1000, 1500, 2500), lwd = "TOTAL_TRIPS", scale=10, palette="-viridis", alpha=0.8) +
tm_shape(sf_BS_167_DIR_1) +
tm_dots(col = "magenta", scale = 3, labels="BS_Code", ) +
tm_text("BS_Code", col="black", size=0.8)+
tm_layout(legend.position = c("right", "top"),
title = result,
title.position = c('right', 'top')
)
tm_objs <- append(tm_objs, list(temp_tm))
i_time = i_time + 1
}
tmap_animation(tm_objs,filename = "data/167_OD_analysis/test.gif", width=2500, height=1500, dpi=200, outer.margins = 0)I guess not very clear so we will analyse at subzone level
5 Data Analysis - Intra-Zonal Flows
Analyse by combining trips into subzone level to have a rough overview
mpsz_pln_area <- st_read(dsn = "data/167_OD_analysis/",
layer = "MP14_PLNG_AREA_WEB_PL") %>%
st_transform(crs = 3414)Reading layer `MP14_PLNG_AREA_WEB_PL' from data source
`C:\Users\boylu\OneDrive - Singapore Management University\0_git-projects\urbancoalesce\explore\data\167_OD_analysis'
using driver `ESRI Shapefile'
Simple feature collection with 55 features and 12 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 2667.538 ymin: 15748.72 xmax: 56396.44 ymax: 50256.33
Projected CRS: SVY21
sf_BS_167_DIR_1_MPSZ <- st_intersection(sf_BS_167_DIR_1, mpsz_pln_area) %>%
select(BS_Code, PLN_AREA_C)
BUS_STOP_DF_MPSZ <- sf_BS_167_DIR_1_MPSZ %>% st_drop_geometry()gen_od_timing_SZ <- function(input_OD, sf_bs, timing){
OD_TEST_DIR1 <- input_OD %>% filter(DAY_TYPE == "WEEKDAY" & TIME_PER_HOUR == timing)
OD_2023_11_DIR1_SZ <- left_join(OD_TEST_DIR1 , sf_bs,
by = c("ORIGIN_PT_CODE" = "BS_Code")) %>%
rename(ORIGIN_BS = ORIGIN_PT_CODE,
ORIGIN_PA = PLN_AREA_C,
DESTIN_BS = DESTINATION_PT_CODE)
OD_2023_11_DIR1_SZ <- left_join(OD_2023_11_DIR1_SZ , sf_bs,
by = c("DESTIN_BS" = "BS_Code"))
OD_2023_11_DIR1_SZ <- OD_2023_11_DIR1_SZ %>%
rename(DESTIN_PA = PLN_AREA_C) %>%
drop_na() %>%
group_by(ORIGIN_PA, DESTIN_PA) %>%
summarise(SZ_TRIPS = sum(TOTAL_TRIPS))
return (OD_2023_11_DIR1_SZ)
}
gen_od_timing_SZ_intra <- function(OD_2023_11_DIR1_SZ){
OD_2023_11_DIR1_SZ_INTRA <- OD_2023_11_DIR1_SZ[OD_2023_11_DIR1_SZ$ORIGIN_PA!=OD_2023_11_DIR1_SZ$DESTIN_PA,]
return (OD_2023_11_DIR1_SZ_INTRA)
}
gen_od_timing_SZ_inter <- function(OD_2023_11_DIR1_SZ){
OD_2023_11_DIR1_SZ_INTER <- OD_2023_11_DIR1_SZ[OD_2023_11_DIR1_SZ$ORIGIN_PA==OD_2023_11_DIR1_SZ$DESTIN_PA,]
return (OD_2023_11_DIR1_SZ_INTER)
}
gen_od_timing_SZ_flows <- function(OD_2023_11_DIR1_SZ_INTRA){
sf_OD_2023_11_DIR1_SZ_INTRA_FLOWS <- od2line(flow = OD_2023_11_DIR1_SZ_INTRA,
zones = mpsz_pln_area,
zone_code = "PLN_AREA_C")
return (sf_OD_2023_11_DIR1_SZ_INTRA_FLOWS)
}
tmap_plot_sz <- function(BS, OD) {
tmap_mode("view")
tm_shape(mpsz_pln_area) +
tm_polygons("PLN_AREA_C", legend.show = FALSE, palette="Set3") +
tm_shape(BS) +
tm_dots("PLN_AREA_C", scale = 1.3, legend.show = FALSE, palette="Set3") +
#tm_shape(sf_BS_167_DIR_2) +
# tm_dots(col = "blue", scale = 2) +
tm_shape(OD) +
tm_lines(col = "SZ_TRIPS", style="fixed", breaks = c(0, 25, 50, 100, 250, 500, 700, 1000, 1500, 2500), lwd = "SZ_TRIPS", scale=15, palette="viridis")
}
plot_trip_summary <- function(OD){
summary(OD$SZ_TRIPS)
p <- ggplot(OD, aes(x=SZ_TRIPS)) +
geom_histogram(binwidth=100) +
xlim(0, 2500) +
ylim(0, 400)
ggplotly(p)
}tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 6)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 56 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 AM BS 1370 LINESTRING (28976.88 40229....
2 YS AM 1153 LINESTRING (28404.04 44086....
3 NT OR 1064 LINESTRING (28529.66 32330....
4 SB YS 862 LINESTRING (26387.4 48594.6...
5 BS TP 446 LINESTRING (28789.76 37450....
6 NV OR 410 LINESTRING (28221.51 34356....
7 MU DT 387 LINESTRING (29490.79 30921....
8 YS BS 324 LINESTRING (28404.04 44086....
9 NV NT 293 LINESTRING (28221.51 34356....
10 BS NV 216 LINESTRING (28789.76 37450....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 26
2 BM BM 634
3 BS BS 453
4 DT DT 167
5 MU MU 330
6 NT NT 161
7 NV NV 90
8 OR OR 217
9 SB SB 107
10 TP TP 92
11 YS YS 1683
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 7)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 58 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 YS AM 3742 LINESTRING (28404.04 44086....
2 AM BS 2510 LINESTRING (28976.88 40229....
3 NV NT 1697 LINESTRING (28221.51 34356....
4 NT OR 1648 LINESTRING (28529.66 32330....
5 SB YS 1303 LINESTRING (26387.4 48594.6...
6 MU DT 932 LINESTRING (29490.79 30921....
7 BS TP 847 LINESTRING (28789.76 37450....
8 NV OR 762 LINESTRING (28221.51 34356....
9 NV DT 630 LINESTRING (28221.51 34356....
10 BS NV 616 LINESTRING (28789.76 37450....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 128
2 BM BM 1996
3 BS BS 1371
4 DT DT 505
5 MU MU 758
6 NT NT 64
7 NV NV 253
8 OR OR 535
9 SB SB 301
10 TP TP 373
11 YS YS 3205
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 8)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 58 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 YS AM 6481 LINESTRING (28404.04 44086....
2 NV NT 3091 LINESTRING (28221.51 34356....
3 AM BS 2760 LINESTRING (28976.88 40229....
4 MU DT 2712 LINESTRING (29490.79 30921....
5 NT OR 2559 LINESTRING (28529.66 32330....
6 NV OR 2225 LINESTRING (28221.51 34356....
7 SB YS 1267 LINESTRING (26387.4 48594.6...
8 OR DT 984 LINESTRING (28029.14 31793....
9 OR MU 923 LINESTRING (28029.14 31793....
10 NV DT 881 LINESTRING (28221.51 34356....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 95
2 BM BM 2174
3 BS BS 1876
4 DT DT 1340
5 MU MU 2272
6 NT NT 82
7 NV NV 620
8 OR OR 1124
9 SB SB 578
10 TP TP 370
11 YS YS 3607
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 9)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 59 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 NT OR 2835 LINESTRING (28529.66 32330....
2 YS AM 1931 LINESTRING (28404.04 44086....
3 AM BS 1823 LINESTRING (28976.88 40229....
4 NV OR 1814 LINESTRING (28221.51 34356....
5 NV NT 1642 LINESTRING (28221.51 34356....
6 MU DT 1603 LINESTRING (29490.79 30921....
7 SB YS 1145 LINESTRING (26387.4 48594.6...
8 OR MU 1112 LINESTRING (28029.14 31793....
9 OR DT 683 LINESTRING (28029.14 31793....
10 BS TP 451 LINESTRING (28789.76 37450....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 94
2 BM BM 1710
3 BS BS 1334
4 DT DT 1313
5 MU MU 1509
6 NT NT 31
7 NV NV 325
8 OR OR 973
9 SB SB 361
10 TP TP 176
11 YS YS 1872
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 10)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 59 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 NT OR 3056 LINESTRING (28529.66 32330....
2 NV OR 1687 LINESTRING (28221.51 34356....
3 AM BS 1254 LINESTRING (28976.88 40229....
4 OR MU 1201 LINESTRING (28029.14 31793....
5 SB YS 931 LINESTRING (26387.4 48594.6...
6 MU DT 785 LINESTRING (29490.79 30921....
7 YS AM 771 LINESTRING (28404.04 44086....
8 NV NT 769 LINESTRING (28221.51 34356....
9 OR DT 505 LINESTRING (28029.14 31793....
10 DT BM 415 LINESTRING (30335.19 29721....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 71
2 BM BM 1360
3 BS BS 952
4 DT DT 770
5 MU MU 793
6 NT NT 13
7 NV NV 301
8 OR OR 656
9 SB SB 270
10 TP TP 70
11 YS YS 1651
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 11)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 62 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 NT OR 3700 LINESTRING (28529.66 32330....
2 NV OR 2070 LINESTRING (28221.51 34356....
3 OR MU 1743 LINESTRING (28029.14 31793....
4 AM BS 1326 LINESTRING (28976.88 40229....
5 SB YS 912 LINESTRING (26387.4 48594.6...
6 NV NT 866 LINESTRING (28221.51 34356....
7 MU DT 862 LINESTRING (29490.79 30921....
8 DT BM 736 LINESTRING (30335.19 29721....
9 OR DT 566 LINESTRING (28029.14 31793....
10 BS NV 420 LINESTRING (28789.76 37450....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 200
2 BM BM 1289
3 BS BS 1066
4 DT DT 961
5 MU MU 632
6 NT NT 30
7 NV NV 474
8 OR OR 936
9 SB SB 332
10 TP TP 82
11 YS YS 1880
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 12)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 59 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 NT OR 7266 LINESTRING (28529.66 32330....
2 OR MU 2589 LINESTRING (28029.14 31793....
3 NV OR 1917 LINESTRING (28221.51 34356....
4 AM BS 1197 LINESTRING (28976.88 40229....
5 MU DT 971 LINESTRING (29490.79 30921....
6 DT BM 939 LINESTRING (30335.19 29721....
7 SB YS 815 LINESTRING (26387.4 48594.6...
8 NV NT 814 LINESTRING (28221.51 34356....
9 OR DT 667 LINESTRING (28029.14 31793....
10 YS AM 534 LINESTRING (28404.04 44086....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 306
2 BM BM 1500
3 BS BS 1167
4 DT DT 1100
5 MU MU 940
6 NT NT 16
7 NV NV 349
8 OR OR 1229
9 SB SB 443
10 TP TP 114
11 YS YS 2340
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 18)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 60 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 OR MU 8137 LINESTRING (28029.14 31793....
2 DT BM 3881 LINESTRING (30335.19 29721....
3 AM BS 2427 LINESTRING (28976.88 40229....
4 NT OR 1952 LINESTRING (28529.66 32330....
5 NV OR 1635 LINESTRING (28221.51 34356....
6 SB YS 1208 LINESTRING (26387.4 48594.6...
7 NV NT 1188 LINESTRING (28221.51 34356....
8 MU DT 1123 LINESTRING (29490.79 30921....
9 YS AM 868 LINESTRING (28404.04 44086....
10 OR DT 742 LINESTRING (28029.14 31793....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 319
2 BM BM 2739
3 BS BS 1647
4 DT DT 1674
5 MU MU 1283
6 NT NT 18
7 NV NV 415
8 OR OR 1295
9 SB SB 794
10 TP TP 291
11 YS YS 3133
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 19)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 57 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 OR MU 5900 LINESTRING (28029.14 31793....
2 DT BM 2508 LINESTRING (30335.19 29721....
3 NT OR 1174 LINESTRING (28529.66 32330....
4 AM BS 1055 LINESTRING (28976.88 40229....
5 NV OR 993 LINESTRING (28221.51 34356....
6 SB YS 862 LINESTRING (26387.4 48594.6...
7 YS AM 791 LINESTRING (28404.04 44086....
8 MU DT 725 LINESTRING (29490.79 30921....
9 NV NT 713 LINESTRING (28221.51 34356....
10 OR BM 519 LINESTRING (28029.14 31793....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 77
2 BM BM 2449
3 BS BS 914
4 DT DT 862
5 MU MU 1031
6 NT NT 6
7 NV NV 295
8 OR OR 1026
9 SB SB 642
10 TP TP 156
11 YS YS 1558
tmap_options(check.and.fix = TRUE)
temp_sf_sz <- gen_od_timing_SZ(OD_2023_11_DIR1, BUS_STOP_DF_MPSZ, 20)
temp_sf_sz_intra <- gen_od_timing_SZ_intra(temp_sf_sz)
temp_sf_sz_inter <- gen_od_timing_SZ_inter(temp_sf_sz)
temp_sf_sz_intra_flows <- gen_od_timing_SZ_flows(temp_sf_sz_intra)
tmap_plot_sz(sf_BS_167_DIR_1_MPSZ, temp_sf_sz_intra_flows)temp_sf_sz_intra_flows %>% arrange(desc(SZ_TRIPS))Simple feature collection with 57 features and 3 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 26387.4 ymin: 28662.87 xmax: 31083.53 ymax: 48594.64
Projected CRS: SVY21 / Singapore TM
First 10 features:
ORIGIN_PA DESTIN_PA SZ_TRIPS geometry
1 OR MU 4712 LINESTRING (28029.14 31793....
2 DT BM 1716 LINESTRING (30335.19 29721....
3 SB YS 677 LINESTRING (26387.4 48594.6...
4 OR BM 548 LINESTRING (28029.14 31793....
5 AM BS 517 LINESTRING (28976.88 40229....
6 NT OR 510 LINESTRING (28529.66 32330....
7 NV NT 466 LINESTRING (28221.51 34356....
8 NV OR 446 LINESTRING (28221.51 34356....
9 YS AM 438 LINESTRING (28404.04 44086....
10 OR DT 357 LINESTRING (28029.14 31793....
plot_trip_summary(temp_sf_sz_intra_flows)temp_sf_sz_inter# A tibble: 11 × 3
# Groups: ORIGIN_PA [11]
ORIGIN_PA DESTIN_PA SZ_TRIPS
<chr> <chr> <int>
1 AM AM 46
2 BM BM 1760
3 BS BS 503
4 DT DT 486
5 MU MU 650
6 NT NT 3
7 NV NV 109
8 OR OR 648
9 SB SB 337
10 TP TP 72
11 YS YS 1093
Todo list:
Visualisation tmap for Subzone / bus stop see how to display data
EDA on trip - derivation on initial analysis (eg. focus on AM Peak Dir 1?)
- Sequential trial and error, might be worthwhile to check off peak trends as well - without data cannot determine which user group but maybe can guess?
K-means clustering on types of stops based on temporal data - each stop, pattern based on day type